/*
 * Copyright 2005-2007 Noelios Consulting.
 * 
 * The contents of this file are subject to the terms of the Common Development
 * and Distribution License (the "License"). You may not use this file except in
 * compliance with the License.
 * 
 * You can obtain a copy of the license at
 * http://www.opensource.org/licenses/cddl1.txt See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing Covered Code, include this CDDL HEADER in each file and
 * include the License file at http://www.opensource.org/licenses/cddl1.txt If
 * applicable, add the following below this CDDL HEADER, with the fields
 * enclosed by brackets "[]" replaced with your own identifying information:
 * Portions Copyright [yyyy] [name of copyright owner]
 */

package com.noelios.restlet.http;

import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;

import org.restlet.Context;
import org.restlet.Server;

import com.noelios.restlet.ServerHelper;

/**
 * Base HTTP server connector. Here is the list of parameters that are
 * supported: <table>
 * <tr>
 * <th>Parameter name</th>
 * <th>Value type</th>
 * <th>Default value</th>
 * <th>Description</th>
 * </tr>
 * <tr>
 * <td>useForwardedForHeader</td>
 * <td>boolean</td>
 * <td>false</td>
 * <td>Lookup the "X-Forwarded-For" header supported by popular proxies and
 * caches and uses it to populate the Request.getClientAddresses() method
 * result. This information is only safe for intermediary components within your
 * local network. Other addresses could easily be changed by setting a fake
 * header and should not be trusted for serious security checks.</td>
 * </tr>
 * <tr>
 * <td>converter</td>
 * <td>String</td>
 * <td>com.noelios.restlet.http.HttpServerConverter</td>
 * <td>Class name of the converter of low-level HTTP calls into high level
 * requests and responses.</td>
 * </tr>
 * </table>
 * 
 * @author Jerome Louvel (contact@noelios.com)
 */
public class HttpServerHelper extends ServerHelper {
    /** The converter from HTTP calls to uniform calls. */
    private HttpServerConverter converter;

    /**
     * Default constructor. Note that many methods assume that a non-null server
     * is set to work properly. You can use the {@link #setServer} method for
     * this purpose or better rely on the other constructor.
     */
    public HttpServerHelper() {
        this(null);
    }

    /**
     * Constructor.
     * 
     * @param server
     *            The server to help.
     */
    public HttpServerHelper(Server server) {
        super(server);
        this.converter = null;
    }

    /**
     * Handles the connector call.<br/> The default behavior is to create an
     * REST call and delegate it to the attached Restlet.
     * 
     * @param httpCall
     *            The HTTP server call.
     */
    public void handle(HttpServerCall httpCall) {
        try {
            HttpRequest request = getConverter().toRequest(httpCall);
            HttpResponse response = new HttpResponse(httpCall, request);
            handle(request, response);
            getConverter().commit(response);
        } catch (Exception e) {
            getLogger().log(Level.WARNING,
                    "Error while handling an HTTP server call: ",
                    e.getMessage());
            getLogger().log(Level.INFO,
                    "Error while handling an HTTP server call", e);
        }
    }

    /**
     * Returns the converter from HTTP calls to uniform calls.
     * 
     * @return the converter from HTTP calls to uniform calls.
     */
    public HttpServerConverter getConverter() {
        if (this.converter == null) {
            try {
                String converterClass = getParameters().getFirstValue(
                        "converter",
                        "com.noelios.restlet.http.HttpServerConverter");
                this.converter = (HttpServerConverter) Class.forName(
                        converterClass).getConstructor(Context.class)
                        .newInstance(getContext());
            } catch (IllegalArgumentException e) {
                getLogger().log(Level.SEVERE,
                        "Unable to create the HTTP server converter", e);
            } catch (SecurityException e) {
                getLogger().log(Level.SEVERE,
                        "Unable to create the HTTP server converter", e);
            } catch (InstantiationException e) {
                getLogger().log(Level.SEVERE,
                        "Unable to create the HTTP server converter", e);
            } catch (IllegalAccessException e) {
                getLogger().log(Level.SEVERE,
                        "Unable to create the HTTP server converter", e);
            } catch (InvocationTargetException e) {
                getLogger().log(Level.SEVERE,
                        "Unable to create the HTTP server converter", e);
            } catch (NoSuchMethodException e) {
                getLogger().log(Level.SEVERE,
                        "Unable to create the HTTP server converter", e);
            } catch (ClassNotFoundException e) {
                getLogger().log(Level.SEVERE,
                        "Unable to create the HTTP server converter", e);
            }
        }

        return this.converter;
    }

    /**
     * Sets the converter from HTTP calls to uniform calls.
     * 
     * @param converter
     *            The converter to set.
     */
    public void setConverter(HttpServerConverter converter) {
        this.converter = converter;
    }
}
